﻿using System;
using System.Diagnostics;
using System.Threading.Tasks;
using GalaSoft.MvvmLight.Messaging;
using Windows.Foundation;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

namespace Wp7nl.Devices
{
  public class TtcSocketHelper
  {
    private readonly object lockObject = new object();

    public TtcSocketHelper()
    {
      Messenger.Default.Register<NavigationMessage>(this, ProcessNavigationMessage);
    }

    public void Start()
    {
      PeerFinder.TriggeredConnectionStateChanged += PeerFinderTriggeredConnectionStateChanged;

      PeerFinder.AllowBluetooth = true;
      PeerFinder.Start();
    }

    private async void StartListeningForMessages()
    {
      if( socket != null )
      {
        if (!listening)
        {
          listening = true;
          while (listening)
          {
            var message = await GetMessage();
            if (listening)
            {
              if (message != null && MessageReceived != null)
              {
                MessageReceived(this, new ReceivedMessageEventArgs {Message = message});
              }
            }
          }
        }
      }
    }


    public async void SendMessage(string message)
    {
      Debug.WriteLine("Send message:" + message);
      if (socket != null)
      {
        try
        {
          lock (lockObject)
          {
            {
              if (dataWriter == null)
              {
                dataWriter = new DataWriter(socket.OutputStream);
              }

              dataWriter.WriteInt32(message.Length);
              dataWriter.StoreAsync();

              dataWriter.WriteString(message);
              dataWriter.StoreAsync();
            }
          }
        }
        catch (Exception ex)
        {
          Debug.WriteLine("SendMessage: " + ex.Message);
        }
      }
    }

    public void Reset()
    {
      PeerFinder.Stop();
      if (dataReader != null)
      {
        try
        {
          listening = false;
          if (dataReader != null)
          {
            dataReader.Dispose();
            dataReader = null;
          }
          if (dataWriter != null)
          {
            dataWriter.Dispose();
            dataWriter = null;
          }
          if (socket != null)
          {
            socket.Dispose();
            socket = null;
          }
        }
        catch (Exception ex)
        {
        }
      }
    }

    private void ProcessNavigationMessage(NavigationMessage message)
    {
      Debug.WriteLine("TtsHelper.ProcessNavigationMessage " + message.NavigationEvent.Uri);

      if (message.IsStartedByNfcRequest)
      {
        Start();
      }
    }


    private void PeerFinderTriggeredConnectionStateChanged(object sender, TriggeredConnectionStateChangedEventArgs args)
    {
      switch (args.State)
      {
        case TriggeredConnectState.Completed: // Connection completed, get the socket
          FireConnectionStatusChanged(args);
          socket = args.Socket;
          StartListeningForMessages();
          PeerFinder.Stop();
          break;
        default:
          FireConnectionStatusChanged(args);
          break;
      }
    }

    private void FireConnectionStatusChanged(TriggeredConnectionStateChangedEventArgs args)
    {
      Debug.WriteLine("TtsHelper: " + args);
      if (ConnectionStatusChanged != null)
      {
        ConnectionStatusChanged(this, args );
      }
    }

    private async Task<string> GetMessage()
    {
      try
      {
        if (dataReader == null) dataReader = new DataReader(socket.InputStream);
        await dataReader.LoadAsync(4);
        var messageLen = (uint)dataReader.ReadInt32();

        await dataReader.LoadAsync(messageLen);
        var message = dataReader.ReadString(messageLen);
        Debug.WriteLine("Message received: " + message);

        return message;
      }
      catch (Exception ex)
      {
        Debug.WriteLine("GetMessage: " + ex.Message);
      }
      return null;

    }

    public event TypedEventHandler<object, TriggeredConnectionStateChangedEventArgs> ConnectionStatusChanged;

    public event TypedEventHandler<object, ReceivedMessageEventArgs> MessageReceived;

    private StreamSocket socket;

    private DataReader dataReader;

    private DataWriter dataWriter;

    private bool listening;
  }
}
